package com.zezheng.extract.common.utils;

import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Lists;
import org.docx4j.fonts.IdentityPlusMapper;
import org.docx4j.fonts.Mapper;
import org.docx4j.fonts.PhysicalFonts;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.wml.ContentAccessor;
import org.docx4j.wml.Text;

import javax.xml.bind.JAXBElement;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class WordToPdf {


    public static List<Object> getAllElementFromObject(Object obj,
                                                       Class<?> toSearch) {
        List<Object> result = Lists.newArrayListWithCapacity(60);
        if (obj instanceof JAXBElement) {
            obj = ((JAXBElement<?>) obj).getValue();
        }
        if (obj.getClass().equals(toSearch)) {
            result.add(obj);
        } else if (obj instanceof ContentAccessor) {
            List<?> children = ((ContentAccessor) obj).getContent();
            for (Object child : children) {
                result.addAll(getAllElementFromObject(child, toSearch));
            }
        }
        return result;
    }

    private static int MAX_TEXT_SIZE = 1000000;

    public static void searchAndReplace(List<Object> texts, Map<String, String> values) {
        // 存储占位符 位置信息集合
        List<int[]> placeholderList = getPlaceholderList(texts, values);
        if (ObjectUtil.isEmpty(placeholderList)) {
            return;
        }
        int[] currentPlaceholder;
        // 删除元素占位符
        for (int i = 0; i < texts.size(); i++) {
            if (ObjectUtil.isEmpty(placeholderList)) {
                break;
            }
            currentPlaceholder = placeholderList.get(0);
            Text textElement = (Text) texts.get(i);
            String v = textElement.getValue();
            StringBuilder nval = new StringBuilder();
            char[] textChars = v.toCharArray();
            for (int j = 0; j < textChars.length; j++) {
                char c = textChars[j];
                if (null == currentPlaceholder) {
                    nval.append(c);
                    continue;
                }
                // 计算是否需要排除当前节点
                int start = currentPlaceholder[0] * MAX_TEXT_SIZE + currentPlaceholder[1];
                int end = currentPlaceholder[2] * MAX_TEXT_SIZE + currentPlaceholder[3];
                int cur = i * MAX_TEXT_SIZE + j;
                // 排除'$'和'}'两个字符之间的字符
                if (!(cur >= start && cur <= end)) {
                    nval.append(c);
                }

                if (j > currentPlaceholder[3] && i >= currentPlaceholder[2]) {
                    placeholderList.remove(0);
                    if (ObjectUtil.isEmpty(placeholderList)) {
                        currentPlaceholder = null;
                        continue;
                    }
                    currentPlaceholder = placeholderList.get(0);
                }
            }
            textElement.setValue(nval.toString());
        }
    }

    public static List<String> getTagList(List<Object> texts) {
        // 标识忽略
        int ignoreTg = 0;
        // 标识已读取到'$'字符
        int startTg = 1;
        // 标识已读取到'{'字符
        int readTg = 2;
        // 当前标识
        int modeTg = ignoreTg;
        List<String> list = new ArrayList<>();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < texts.size(); i++) {
            Text textElement = (Text) texts.get(i);
            String newVal = "";
            String text = textElement.getValue();
            StringBuilder textSofar = new StringBuilder();
            char[] textChars = text.toCharArray();
            for (int col = 0; col < textChars.length; col++) {
                char c = textChars[col];
                textSofar.append(c);
                switch (c) {
                    case '$': {
                        modeTg = startTg;
                        sb.append(c);
                    }
                    break;
                    case '{': {
                        if (modeTg == startTg) {
                            sb.append(c);
                            modeTg = readTg;
                        } else {
                            if (modeTg == readTg) {
                                sb = new StringBuilder();
                                modeTg = ignoreTg;
                            }
                        }
                    }
                    break;
                    case '}': {
                        if (modeTg == readTg) {
                            modeTg = ignoreTg;
                            sb.append(c);
                            list.add(sb.toString());
                            textSofar = new StringBuilder();
                            sb = new StringBuilder();
                        } else if (modeTg == startTg) {
                            modeTg = ignoreTg;
                            sb = new StringBuilder();
                        }
                    }
                    default: {
                        if (modeTg == readTg) {
                            sb.append(c);
                        } else if (modeTg == startTg) {
                            modeTg = ignoreTg;
                            sb = new StringBuilder();
                        }
                    }
                }
            }
        }
        return list;
    }

    public static List<int[]> getPlaceholderList(List<Object> texts, Map<String, String> values) {
        // 标识忽略
        int ignoreTg = 0;
        // 标识已读取到'$'字符
        int startTg = 1;
        // 标识已读取到'{'字符
        int readTg = 2;
        // 当前标识
        int modeTg = ignoreTg;

        // 存储占位符 位置信息集合
        List<int[]> placeholderList = new ArrayList<>();
        // 当前占位符 0：'$'字符Text在texts中下标
        //          1：'$'字符在Text.getValue().toCharArray()数组下标
        //          2: '}'字符Text在texts中下标
        //          3：'}'字符在Text.getValue().toCharArray()数组下标
        int[] currentPlaceholder = new int[4];
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < texts.size(); i++) {
            Text textElement = (Text) texts.get(i);
            String newVal = "";
            String text = textElement.getValue();
            StringBuilder textSofar = new StringBuilder();
            char[] textChars = text.toCharArray();
            for (int col = 0; col < textChars.length; col++) {
                char c = textChars[col];
                textSofar.append(c);
                switch (c) {
                    case '$': {
                        modeTg = startTg;
                        sb.append(c);
                    }
                    break;
                    case '{': {
                        if (modeTg == startTg) {
                            sb.append(c);
                            modeTg = readTg;
                            currentPlaceholder[0] = i;
                            currentPlaceholder[1] = col - 1;
                        } else {
                            if (modeTg == readTg) {
                                sb = new StringBuilder();
                                modeTg = ignoreTg;
                            }
                        }
                    }
                    break;
                    case '}': {
                        if (modeTg == readTg) {
                            modeTg = ignoreTg;
                            sb.append(c);
                            newVal += textSofar.toString()
                                    + (null == values.get(sb.toString()) ? sb.toString() : values.get(sb.toString()));
                            textSofar = new StringBuilder();
                            currentPlaceholder[2] = i;
                            currentPlaceholder[3] = col;
                            placeholderList.add(currentPlaceholder);
                            currentPlaceholder = new int[4];
                            sb = new StringBuilder();
                        } else if (modeTg == startTg) {
                            modeTg = ignoreTg;
                            sb = new StringBuilder();
                        }
                    }
                    default: {
                        if (modeTg == readTg) {
                            sb.append(c);
                        } else if (modeTg == startTg) {
                            modeTg = ignoreTg;
                            sb = new StringBuilder();
                        }
                    }
                }
            }
            newVal += textSofar.toString();
            textElement.setValue(newVal);
        }
        return placeholderList;
    }

    public static void fontMapper(WordprocessingMLPackage wordMLPackage) throws Exception {
        Mapper fontMapper = new IdentityPlusMapper();
        fontMapper.put("隶书", PhysicalFonts.get("LiSu"));
        fontMapper.put("宋体", PhysicalFonts.get("SimSun"));
        fontMapper.put("微软雅黑", PhysicalFonts.get("Microsoft Yahei"));
        fontMapper.put("黑体", PhysicalFonts.get("SimHei"));
        fontMapper.put("楷体", PhysicalFonts.get("KaiTi"));
        fontMapper.put("新宋体", PhysicalFonts.get("NSimSun"));
        fontMapper.put("华文行楷", PhysicalFonts.get("STXingkai"));
        fontMapper.put("华文仿宋", PhysicalFonts.get("STFangsong"));
        fontMapper.put("仿宋", PhysicalFonts.get("FangSong"));
        fontMapper.put("幼圆", PhysicalFonts.get("YouYuan"));
        fontMapper.put("华文宋体", PhysicalFonts.get("STSong"));
        fontMapper.put("华文中宋", PhysicalFonts.get("STZhongsong"));
        fontMapper.put("等线", PhysicalFonts.get("SimSun"));
        fontMapper.put("等线 Light", PhysicalFonts.get("SimSun"));
        fontMapper.put("华文琥珀", PhysicalFonts.get("STHupo"));
        fontMapper.put("华文隶书", PhysicalFonts.get("STLiti"));
        fontMapper.put("华文新魏", PhysicalFonts.get("STXinwei"));
        fontMapper.put("华文彩云", PhysicalFonts.get("STCaiyun"));
        fontMapper.put("方正姚体", PhysicalFonts.get("FZYaoti"));
        fontMapper.put("方正舒体", PhysicalFonts.get("FZShuTi"));
        fontMapper.put("华文细黑", PhysicalFonts.get("STXihei"));
        fontMapper.put("宋体扩展", PhysicalFonts.get("simsun-extB"));
        fontMapper.put("仿宋_GB2312", PhysicalFonts.get("FangSong_GB2312"));
        fontMapper.put("新細明體", PhysicalFonts.get("SimSun"));
        PhysicalFonts.put("PMingLiU", PhysicalFonts.get("SimSun"));
        PhysicalFonts.put("新細明體", PhysicalFonts.get("SimSun"));
        wordMLPackage.setFontMapper(fontMapper);
    }
}
